package com.gua.jbs.serviceImpl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.gua.jbs.bean.OrderBean;
import com.gua.jbs.bean.ProductBean;
import com.gua.jbs.controller.BillController;
import com.gua.jbs.dao.IOrderDao;
import com.gua.jbs.daoImpl.OrderDao;
import com.gua.jbs.pojo.Jbsoht;
import com.gua.jbs.pojo.Jbsoit;
import com.gua.jbs.pojo.MainOrder;
import com.gua.jbs.pojo.SubOrder;
import com.gua.jbs.service.IInvoiceService;
import com.gua.jbs.service.IOrderService;
import com.gua.jbs.service.IProductService;
import com.gua.jbs.service.IStockService;
import com.gua.jbs.utility.ApplicationConstant;
import com.gua.jbs.utility.ApplicationException;
import com.gua.jbs.utility.CollectionUtil;
import com.gua.jbs.utility.DBConstant;
import com.gua.jbs.utility.ExceptionMessage;
import com.gua.jbs.utility.StringUtil;

public class OrderService extends BaseService implements IOrderService {
	private static final Logger logger = Logger.getLogger(OrderService.class);
	private IOrderDao orderDao = null;
	private IProductService productService = null;
	private IStockService stockService = null;
	private IInvoiceService iInvoiceService = null;

	public OrderService() {
		orderDao = new OrderDao();
		productService = new ProductService();
		stockService = new StockService();
		iInvoiceService = new InvoiceService();
	}

	/**
	 * Method to save the orders
	 * 
	 * @param orderObject
	 * @throws ApplicationException
	 */
	public void prepareOrder(OrderBean orderObject) throws ApplicationException {
		Jbsoit jbsoit = null;
		List<Integer> pkList = new ArrayList<Integer>();
		int pk = 0;
		Integer quantity = 0;
		try {
			if (orderObject != null) {
				MainOrder mainOrder = prepareMainOrder(orderObject);

				// Process Sub Orders
				List<SubOrder> subOrderList = prepareSubOrders(orderObject);
				if (!CollectionUtil.isEmptyList(subOrderList)) {
					for (int counter = 0; counter < subOrderList.size(); counter++) {
						jbsoit = createToBeSavedSubOrderObject(subOrderList
								.get(counter));

						// Save sub-orders
						pk = orderDao.saveOrder(jbsoit);
						pkList.add(pk);
						if (pk == 0)
							throw new ApplicationException(
									ExceptionMessage.ORDER_NOT_SAVED);
						quantity = quantity
								+ Integer.parseInt(jbsoit.getProdQuantity());

						/**
						 * Reduce the stock in the product stock table
						 */
						reduceStock(jbsoit.getProdId(),
								jbsoit.getProdQuantity());
					}
				}

				// Process Main Order
				jbsoit = createToBeSavedMainOrderObject(mainOrder);
				jbsoit.setProdQuantity("" + quantity);
				// Save main order
				pk = orderDao.saveOrder(jbsoit);

				// Save order history
				orderDao.saveOrderHistory("" + pk, ""
						+ DBConstant.ORDER_STATE_UNDER_PROCESS, ""
						+ DBConstant.ORDER_STATE_UNDER_PROCESS);
				// Update the orders for parent Id
				if (!CollectionUtil.isEmptyList(pkList)) {
					for (int counter = 0; counter < pkList.size(); counter++) {
						orderDao.updateOrderForParent("" + pk,
								"" + pkList.get(counter));
					}
				}

				// Update the Invoice number after processing
				if (StringUtil.isNullOrEmpty(mainOrder.getInvoiceNumber())) {
					String invoiceValArray[] = mainOrder.getInvoiceNumber()
							.split("/");
					String updateValue = ""
							+ (Integer.parseInt(invoiceValArray[2]) + 1);
					iInvoiceService.updateInvoiceNumber(updateValue);
				}
			}
		} catch (ApplicationException ae) {
			logger.error("OrderService : prepareOrder() ----> "
					+ ae.getMessage());
			throw new ApplicationException(ExceptionMessage.ORDER_NOT_SAVED);
		}

	}

	/**
	 * Private Method to prepare the Main Order
	 * 
	 * @param orderObject
	 * @return
	 * @throws ApplicationException
	 */
	private MainOrder prepareMainOrder(OrderBean orderObject)
			throws ApplicationException {
		MainOrder mainOrder = null;
		try {
			if (orderObject != null) {
				mainOrder = new MainOrder();
				mainOrder.setCustomerId(orderObject.getCustomerId());
				mainOrder.setDiscountPerc(orderObject.getDiscountPerc());
				mainOrder.setFinalPrice(orderObject.getFinalPrice());
				mainOrder.setCourierCharges(orderObject.getCourierCharges());
				mainOrder.setInvoiceNumber(orderObject.getInvoiceNumber());
				mainOrder.setIsMainOrder(DBConstant.IS_PARENT_YES);
				mainOrder.setOrderServiceTax(orderObject.getOrderServiceTax());
				mainOrder.setOrderstate(DBConstant.ORDER_STATE_UNDER_PROCESS);
				mainOrder.setPaymentMode(orderObject.getPaymentMode());
				mainOrder.setTotalPrice(orderObject.getTotalPrice());
				mainOrder.setReferenceNo(orderObject.getReference());
			}
		} catch (Exception e) {
			logger.error("OrderService : prepareMainOrder() ----> "
					+ e.getMessage());
		}
		return mainOrder;
	}

	/**
	 * Private method to get the POJO object for main order
	 * 
	 * @param mainOrder
	 * @return
	 * @throws ApplicationException
	 */
	private Jbsoit createToBeSavedMainOrderObject(MainOrder mainOrder)
			throws ApplicationException {
		Jbsoit jbsoit = null;
		try {
			if (mainOrder != null) {
				jbsoit = new Jbsoit();
				jbsoit.setCouponId(null);
				jbsoit.setCustId(mainOrder.getCustomerId());
				if (StringUtil.isNullOrEmpty(mainOrder.getDiscountPerc())) {
					jbsoit.setIsDiscount(DBConstant.IS_DISCOUNT_YES);
					jbsoit.setDiscountPercentage(mainOrder.getDiscountPerc());
				}
				jbsoit.setIsMainOrder(DBConstant.IS_MAIN_ORDER_YES);

				// As it is main order
				jbsoit.setParentId(null);
				jbsoit.setPaymentMode(mainOrder.getPaymentMode());
				jbsoit.setExtrafield1(mainOrder.getCourierCharges());
				jbsoit.setExtrafield2(mainOrder.getInvoiceNumber());
				jbsoit.setExtrafield3("" + mainOrder.getOrderServiceTax());
				jbsoit.setReferenceNo(mainOrder.getReferenceNo());
				jbsoit.setPurchaseAmount(mainOrder.getTotalPrice());
				jbsoit.setTotalPrice(mainOrder.getFinalPrice());
				jbsoit.setPurchaseDate(new java.sql.Date(System
						.currentTimeMillis()));
			}
		} catch (Exception e) {
			logger.error("OrderService : createToBeSavedMainOrderObject() ----> "
					+ e.getMessage());
			throw new ApplicationException(
					ExceptionMessage.ORDER_OBJECT_CREATION_PROBLEM);
		}
		return jbsoit;
	}

	/**
	 * Private method to prepare pojo object for sub order
	 * 
	 * @param mainOrder
	 * @return
	 * @throws ApplicationException
	 */
	private Jbsoit createToBeSavedSubOrderObject(SubOrder subOrder)
			throws ApplicationException {
		Jbsoit jbsoit = null;
		try {
			if (subOrder != null) {
				jbsoit = new Jbsoit();
				/**
				 * To Do
				 */
				/*
				 * String couponCode = request
				 * .getParameter(ApplicationConstant.COUPON_CODE); if
				 * (StringUtil.isNullOrEmpty(couponCode)) { CouponBean
				 * couponBean = null; try { couponBean = couponService
				 * .getCouponInfo(couponCode);
				 * //orderObject.setCouponId(Integer.parseInt(couponBean
				 * //.getCouponId())); } catch (ApplicationException ae) { // To
				 * Do : Throw Exception } }
				 */
				jbsoit.setCouponId(subOrder.getCouponId());
				jbsoit.setIsMainOrder(DBConstant.IS_MAIN_ORDER_NO);
				jbsoit.setProdQuantity(subOrder.getQuantity());
				jbsoit.setPurchaseAmount(subOrder.getPurchaseAmt());
				if (StringUtil.isNullOrEmpty(subOrder.getQuantity())
						&& StringUtil.isNullOrEmpty(subOrder.getPurchaseAmt())) {
					Double amount = Double.parseDouble(subOrder
							.getPurchaseAmt());
					Integer quantity = Integer.parseInt(subOrder.getQuantity());
					Double totalPrice = amount * quantity;
					jbsoit.setTotalPrice("" + totalPrice);
				}
				jbsoit.setPurchaseDate(new java.sql.Date(System
						.currentTimeMillis()));
				jbsoit.setProdId(subOrder.getProdId());
				jbsoit.setCustId(subOrder.getCustId());
			}
		} catch (Exception e) {
			logger.error("OrderService : createToBeSavedMainOrderObject() ----> "
					+ e.getMessage());
		}
		return jbsoit;
	}

	/**
	 * Private Method to prepare Sub-Order List
	 * 
	 * @param orderObject
	 * @return
	 * @throws ApplicationException
	 */
	private List<SubOrder> prepareSubOrders(OrderBean orderObject)
			throws ApplicationException {
		List<SubOrder> subOrderList = null;
		if (orderObject != null) {
			// Prepare SubOrder List
			subOrderList = new ArrayList<SubOrder>();
			Map<String, List<String>> contentMap = orderObject
					.getOrderContentMap();
			if (contentMap != null && contentMap.isEmpty() != true) {
				for (int counter = 0; counter < contentMap.size(); counter++) {
					List<String> orderContentList = contentMap
							.get(ApplicationConstant.ORDER + counter);
					if (!CollectionUtil.isEmptyList(orderContentList)) {
						String prodCode = "" + orderContentList.get(0);
						String prodQuantity = "" + orderContentList.get(1);
						String prodPrice = "" + orderContentList.get(2);
						SubOrder subOrder = new SubOrder();
						// subOrder.setCouponId(couponId);
						// subOrder.setDiscount(discount);
						subOrder.setOrderstate(DBConstant.ORDER_STATE_UNDER_PROCESS);
						if (StringUtil.isNullOrEmpty(prodCode)) {
							ProductBean productBean = null;
							try {
								// Call product service to get the product
								// information
								// by
								// its barcode
								productBean = productService
										.getProductByCode(prodCode);
								subOrder.setProdId(productBean.getId());
							} catch (ApplicationException ae) {
								throw new ApplicationException(
										ExceptionMessage.PRODUCT_NOT_IN_SYSTEM);
							}
						}
						subOrder.setPurchaseAmt(prodPrice);
						subOrder.setQuantity(prodQuantity);
						subOrder.setCustId(orderObject.getCustomerId());
						subOrderList.add(subOrder);
					}
				}
			}
		}
		return subOrderList;
	}

	/**
	 * Method to create order content from Json string
	 * 
	 * @param custProdInfo
	 * @return
	 * @throws ApplicationException
	 */
	public Map<String, List<String>> prepareOrderContentMap(String custProdInfo)
			throws ApplicationException {
		Map<String, List<String>> orderValueMap = new HashMap<String, List<String>>();
		try {
			JSONArray jArray = new JSONArray(custProdInfo);
			List ordervalueList = null;
			for (int counter = 0; counter < jArray.length(); counter++) {
				JSONObject object = jArray.getJSONObject(counter);
				ordervalueList = new ArrayList<String>();

				String prodCode = "" + object.get("prodCode");
				String[] newCode = prodCode.split("C");
				if (StringUtil.isNullOrEmpty(prodCode))
					ordervalueList.add(newCode[1]);

				String prodQuantity = "" + object.get("quantity");
				if (StringUtil.isNullOrEmpty(prodQuantity))
					ordervalueList.add(prodQuantity);

				String prodPrice = "" + object.get("prodPrice");
				if (StringUtil.isNullOrEmpty(prodPrice))
					ordervalueList.add(prodPrice);

				orderValueMap.put(ApplicationConstant.ORDER + counter,
						ordervalueList);
			}
		} catch (JSONException e) {
			logger.error("OrderService : prepareOrderContentMap() ----> "
					+ e.getMessage());
			throw new ApplicationException(
					ExceptionMessage.ORDER_CONTENT_NOT_RETRIEVED);
		}
		return orderValueMap;
	}

	public boolean saveOrderState(OrderBean orderObject)
			throws ApplicationException {
		boolean isSaved = false;
		Jbsoht jbsoht = new Jbsoht();
		// jbsoht.setOrderId(orderId);
		// jbsoht.setPrevState(PrevStatus);
		// jbsoht.setPrevState(currentStatus);
		// try {
		// isSaved = orderDao.saveOrderHistory(jbsoht);
		// } catch (ApplicationException ae) {
		// throw ae;
		// }
		return isSaved;
	}

	/**
	 * Reduce the product stock based on the quantity required
	 * 
	 * @param quantity
	 * @param prodId
	 */
	private void reduceStock(String prodId, String quantity)
			throws ApplicationException {
		// Whenever user places an order, state of order is
		// Under
		// Process
		Long orderState = DBConstant.ORDER_STATE_UNDER_PROCESS;
		int requiredQuantity = Integer.parseInt(quantity);
		int currentAvailableQuantity = 0;
		try {
			// call stock service to get the product available
			// stock
			currentAvailableQuantity = stockService.getProductStock(prodId);
			int remainingQuantity = currentAvailableQuantity - requiredQuantity;
			// If demanded quantities are lesser than available then
			// update available quantity with available minus
			// demanded
			// else make available to zero in case demanded is more
			// than
			// available and set the order status as due as products
			// yet
			// to delivered
			if (remainingQuantity < 0)
				orderState = DBConstant.ORDER_STATE_DUE;
			stockService.addStockForProduct(prodId, "" + 0, ""
					+ remainingQuantity);
		} catch (ApplicationException ae) {
			logger.error("OrderService : reduceStock() ----> "
					+ ae.getMessage());
			throw new ApplicationException(
					ExceptionMessage.PRODUCT_STOCK_NOT_ADDED_OR_UPDATED);
		}
	}

	/**
	 * Method that returns all orders of system
	 * 
	 * @return
	 * @throws ApplicationException
	 */
	public List<Object[]> getOrders() throws ApplicationException {
		List<Object[]> orderList = null;
		try {
			orderList = orderDao.getAllActiveOrders();
			/*
			 * if (!CollectionUtil.isEmptyList(orderList)) { orderBeanList = new
			 * ArrayList<OrderBean>(); OrderBean orderBean = null; for (int
			 * counter = 0; counter < orderList.size(); counter++) { orderBean =
			 * new OrderBean(); // orderBean.set } }
			 */
		} catch (ApplicationException ae) {
			logger.error("OrderService : getOrders() ----> " + ae.getMessage());
			throw ae;
		}
		return orderList;
	}
}
